/**
 * @author Jialun Bian
 * @version 1.0
 */
package assembuler;
import java.util.regex.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.file.*;

import userInterface.EnvironmentVariables;



public class Assembuler {
	private static Pattern fdPattern;
	private static Pattern bkPattern;
	private static Pattern ltPattern;
	private static Pattern rtPattern;
	private static Pattern clsPattern;
	private static Pattern puPattern;
	private static Pattern pdPattern;
	private static Pattern setxyPattern;
	private static Pattern setpcPattern;
	private static Pattern setbgPattern;
	private static Pattern stampovalPattern;
	private static Pattern repeatPattern;
	private static Pattern sourcePattern;
	private static Pattern setdPattern;
	private static Pattern setwPattern;
	public static void init() {
		fdPattern = Pattern.compile("^\\s*FD\\s+(\\d+\\.?\\d*)\\s*;?\\s*$",Pattern.CASE_INSENSITIVE);
		bkPattern = Pattern.compile("^\\s*BK\\s+(\\d+\\.?\\d*)\\s*;?\\s*$",Pattern.CASE_INSENSITIVE);
		ltPattern = Pattern.compile("^\\s*LT\\s+(\\d+\\.?\\d*)\\s*;?\\s*$",Pattern.CASE_INSENSITIVE);
		rtPattern = Pattern.compile("^\\s*RT\\s+(\\d+\\.?\\d*)\\s*;?\\s*$",Pattern.CASE_INSENSITIVE);
		clsPattern = Pattern.compile("^\\s*CLS\\s*;?\\s*$",Pattern.CASE_INSENSITIVE);
		puPattern = Pattern.compile("^\\s*PU\\s*;?\\s*$",Pattern.CASE_INSENSITIVE);
		pdPattern = Pattern.compile("^\\s*PD\\s*;?\\s*$",Pattern.CASE_INSENSITIVE);
		setxyPattern = Pattern.compile("^\\s*SETXY\\s+(\\d+\\.?\\d*)\\s*,\\s*(\\d+\\.?\\d*)\\s*;?\\s*$",Pattern.CASE_INSENSITIVE);
		setpcPattern = Pattern.compile("^\\s*SETPC\\s+(\\d+)\\s*,(\\d+)\\s*,\\s*(\\d+)\\s*;?\\s*$",Pattern.CASE_INSENSITIVE);
		setbgPattern = Pattern.compile("^\\s*SETBG\\s+(\\d+)\\s*,(\\d+)\\s*,\\s*(\\d+)\\s*;?\\s*$",Pattern.CASE_INSENSITIVE);
		stampovalPattern = Pattern.compile("^\\s*STAMPOVAL\\s+(\\d+\\.?\\d*)\\s*,\\s*(\\d+\\.?\\d*)\\s*;?\\s*$",Pattern.CASE_INSENSITIVE);
		repeatPattern = Pattern.compile("^\\s*REPEAT\\s+(\\d+)\\s+\\[(.+)\\]$",Pattern.CASE_INSENSITIVE);
		sourcePattern = Pattern.compile("^\\s*source\\s+(\\S+)\\s*$",Pattern.CASE_INSENSITIVE);
		setdPattern = Pattern.compile("^\\s*setd\\s+(\\d+\\.?\\d*)\\s*;?\\s*$",Pattern.CASE_INSENSITIVE);
		setwPattern = Pattern.compile("^\\s*setw\\s+(\\d+\\.?\\d*)\\s*;?\\s*$",Pattern.CASE_INSENSITIVE);
	}
	public static int executeSimpleCodeBlocks(String code) {
		int counter;
		int beginer=0;
		boolean foundCode;
		while (beginer<code.length()) {
			counter=0;
			foundCode=false;
			for (int i=beginer;i<code.length();++i) {
				if (code.charAt(i)==';' && counter==0) {
					executeOneLineCode(code.substring(beginer, i+1),true);
					beginer=i+1;
					foundCode=true;
					break;
				}
				if (code.charAt(i)=='[') {
					counter+=1;
				}
				if (code.charAt(i)==']') {
					counter-=1;
					if (counter==0) {
						executeOneLineCode(code.substring(beginer,i+1),true);
						beginer=i+1;
						foundCode=true;
						break;
					}
				}
			}
			if (!foundCode) {
				executeOneLineCode(code.substring(beginer),true);
				break;
			}
		}
		return 0;
	}
	
	public static int executeCodeFromFile(String path) {
		Path filePath=Paths.get(path);
		String codeBlocks="";
		try (
		InputStream in = Files.newInputStream(filePath);
		BufferedReader reader= new BufferedReader(new InputStreamReader(in))) {
			String line = null;
			while ((line=reader.readLine())!=null) {
				if (line.indexOf("//")!=-1)
					line=line.substring(0, line.indexOf("//"));
				codeBlocks=codeBlocks.concat(line);
			}
			reader.close();
			in.close();
		} catch (IOException x) {
			System.err.println(x);
			return 1;
		}
		return executeSimpleCodeBlocks(codeBlocks);
	}
	
	public static int executeOneLineCode(String code,boolean newCommend) {
		Matcher tmpMatcher;
		if (code.matches("^\\s*$")) {
			return 0;
		}
		tmpMatcher = repeatPattern.matcher(code);
		if (tmpMatcher.find()) {
			int k = new Integer(tmpMatcher.group(1));
			for (int i=0;i<k;++i) {
				executeSimpleCodeBlocks(tmpMatcher.group(2));
			}
			return 0;
		}
		if (EnvironmentVariables.haveAnimation && (EnvironmentVariables.mainPanel.logoIsBusy || newCommend)) {
			EnvironmentVariables.mainPanel.codeBuffer.add(code);
			return 0;
		}
		tmpMatcher = fdPattern.matcher(code);
		if (tmpMatcher.find()) {
			EnvironmentVariables.mainPanel.FD(new Double(tmpMatcher.group(1)));
			return 0;
		}
		tmpMatcher = bkPattern.matcher(code);
		if (tmpMatcher.find()) {
			EnvironmentVariables.mainPanel.BK(new Double(tmpMatcher.group(1)));
			return 0;
		}
		tmpMatcher = ltPattern.matcher(code);
		if (tmpMatcher.find()) {
			EnvironmentVariables.mainPanel.LT(new Double(tmpMatcher.group(1)));
			return 0;
		}
		tmpMatcher = rtPattern.matcher(code);
		if (tmpMatcher.find()) {
			EnvironmentVariables.mainPanel.RT(new Double(tmpMatcher.group(1)));
			return 0;
		}
		tmpMatcher = clsPattern.matcher(code);
		if (tmpMatcher.find()) {
			EnvironmentVariables.mainPanel.CLS();
			return 0;
		}
		tmpMatcher = puPattern.matcher(code);
		if (tmpMatcher.find()) {
			EnvironmentVariables.mainPanel.PU();
			return 0;
		}
		tmpMatcher = pdPattern.matcher(code);
		if (tmpMatcher.find()) {
			EnvironmentVariables.mainPanel.PD();
			return 0;
		}
		tmpMatcher = setxyPattern.matcher(code);
		if (tmpMatcher.find()) {
			EnvironmentVariables.mainPanel.setXY(new Double(tmpMatcher.group(1)), new Double(tmpMatcher.group(2)));
			return 0;
		}
		tmpMatcher = setpcPattern.matcher(code);
		if (tmpMatcher.find()) {
			EnvironmentVariables.mainPanel.setPC(new Integer(tmpMatcher.group(1)), new Integer(tmpMatcher.group(2)),new Integer(tmpMatcher.group(3)));
			return 0;
		}
		tmpMatcher = setbgPattern.matcher(code);
		if (tmpMatcher.find()) {
			EnvironmentVariables.mainPanel.setBG(new Integer(tmpMatcher.group(1)), new Integer(tmpMatcher.group(2)),new Integer(tmpMatcher.group(3)));
			return 0;
		}
		tmpMatcher = stampovalPattern.matcher(code);
		if (tmpMatcher.find()) {
			EnvironmentVariables.mainPanel.stampOVAL(new Double(tmpMatcher.group(1)), new Double(tmpMatcher.group(2)));
			return 0;
		}
		tmpMatcher = sourcePattern.matcher(code);
		if (tmpMatcher.find()) {
			if (executeCodeFromFile(tmpMatcher.group(1))!=0) {
				System.out.format("Wrong At %s \n",code);
				return 1;
			} else {
				return 0;
			}
		}
		tmpMatcher = setdPattern.matcher(code);
		if (tmpMatcher.find()) {
			EnvironmentVariables.mainPanel.setDirection(new Double(tmpMatcher.group(1)));
			return 0;
		}
		tmpMatcher = setwPattern.matcher(code);
		if (tmpMatcher.find()) {
			EnvironmentVariables.mainPanel.setWidth(new Double(tmpMatcher.group(1)));
			return 0;
		}
		System.out.format("Wrong Code!Please check the manual!\nCode:%s\n",code);
		return 1;
	}
}
